using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace CGF
{
    /// <summary>
    /// 外部使用只需调用SetTotalNumber方法配置总数和回调即可：(RectTransform可以替换成绑在Cell上的脚本，将通过OnCellUpdate回调，减少GetComponent的性能消耗)
    /// OnCellUpdate的逻辑实现时，支持设置Celld的不同尺寸，如聊天记录每个消息气泡高度不一样等的情况
    /// SetCellUpdateCallback<RectTransform>(OnCellUpdate);
    /// SetTotalNumber<RectTransform>(100, 0);
    /// Refresh(); //当前显示的全部刷新一遍
    /// Stop(); //立即停止当前的惯性移动状态
    /// 立即跳到某个Cell的位置：
    /// ScrollToHead();
    /// ScrollToEnd();
    /// ScrollToIndex(99);
    /// 监听滑到头的时候
    /// SetScrollToHeadCallback(delegate)
    /// 监听滑到底的时候
    /// SetScrollToEndCallback(delegate)
    [ExecuteInEditMode]
    public class ScrollView : MonoBehaviour
    {
        public class Cell
        {
            public int index;
            public Component component;
            public RectTransform trans;
            private Direction direction;

            public Cell(Direction direction)
            {
                this.direction = direction;
            }

            public float Width
            {
                get
                {
                    if (direction == Direction.Horizontal && component is IScrollViewCell)
                    {
                        return (component as IScrollViewCell).GetCellSize();
                    }

                    return trans.sizeDelta.x;
                }
            }
            
            public float Height
            {
                get
                {
                    if (direction == Direction.Vertical && component is IScrollViewCell)
                    {
                        return (component as IScrollViewCell).GetCellSize();
                    }
                    
                    return trans.sizeDelta.y;
                }
            }
        }

        public class Row
        {
            public Cell[] cells;
            public float x, y;
            private float w, h;
            private ScrollView main;

            public float width
            {
                get { return w; }
                set
                {
                    w = value;
                    for (int i = 0; i < cells.Length; i++)
                    {
                        Cell cell = cells[i];
                        if (cell != null && cell.trans.gameObject.activeSelf && cell.Width > w)
                        {
                            w = cell.Width;
                        }
                    }
                }
            }

            public float height
            {
                get { return h; }
                set
                {
                    h = value;
                    for (int i = 0; i < cells.Length; i++)
                    {
                        Cell cell = cells[i];
                        if (cell != null && cell.trans.gameObject.activeSelf && cell.Height > h)
                        {
                            h = cell.Height;
                        }
                    }
                }
            }

            public Row(ScrollView main, float x, float y)
            {
                this.main = main;
                this.x = x;
                this.y = y;
            }

            public bool IsFull
            {
                get
                {
                    for (int i = 0; i < cells.Length; i++)
                    {
                        Cell cell = cells[i];
                        if (cell.trans && !cell.trans.gameObject.activeSelf)
                        {
                            return false;
                        }
                    }

                    return true;
                }
            }

            public void UpdateCellsPos()
            {
                main.currDir.UpdateCellsPos(x, y, cells);
            }

            public void OnRecycle()
            {
                for (int i = 0; i < cells.Length; i++)
                {
                    Cell cell = cells[i];
                    cell.index = -1;
                    if (cell.trans) cell.trans.gameObject.SetActive(false);
                }
            }

            public void OnReuse(float x, float y, ref int index)
            {
                this.x = x;
                this.y = y;
                for (int i = 0; i < cells.Length; i++)
                {
                    Cell cell = cells[i];
                    if (cell.trans)
                    {
                        if (index >= 0 && index < main.totalDataCount)
                        {
                            if (!cell.trans.gameObject.activeSelf)
                            {
                                cell.trans.gameObject.SetActive(true);
                            }

                            cell.index = index;
                            main.onCellUpdate?.Invoke(cell, index);
                            width = cell.Width;
                            height = cell.Height;
                        }
                        else
                        {
                            if (cell.trans.gameObject.activeSelf)
                            {
                                cell.trans.gameObject.SetActive(false);
                            }
                        }

                        index++;
                    }
                }

                RefreshSize();
                UpdateCellsPos();
            }

            public int GetHeadCellIndex()
            {
                return cells[0].index;
            }

            public int GetEndCellIndex()
            {
                return cells[cells.Length - 1].index;
            }

            public void RefreshSize()
            {
                main.currDir.RefreshSize(cells, ref w, ref h);
            }
        }

        public enum Direction
        {
            Horizontal,
            Vertical
        }

        public enum Alignment
        {
            LeftTop,
            RightTop
        }

        public Direction direction = Direction.Vertical;
        public Alignment alignment = Alignment.LeftTop;
        public RectTransform viewport;
        public RectTransform cellPrefab;
        public int gridNum = 1;
        public Vector2 space = new Vector2(0, 0);

        public RectTransform rectTransform
        {
            get { return transform as RectTransform; }
        }

        internal Queue<Row> pool = new Queue<Row>();
        internal List<Row> rows = new List<Row>();
        internal Vector2 viewportSize;
        internal bool hasTriggerHeadAction, hasTriggerEndAction;
        internal Action _onScrollToHead, _onScrollToEnd;
        internal bool cellsExceedsView;
        internal Row headRow, endRow;
        internal float velocity, velocityScale;
        internal int totalDataCount;

        private ScrollViewDirBase _dirHor, _dirVer;

        private ScrollViewDirBase currDir
        {
            get
            {
                if (direction == Direction.Horizontal)
                {
                    return _dirHor ?? (_dirHor = new ScrollViewDirHorizontal(this));
                }
                else
                {
                    return _dirVer ?? (_dirVer = new ScrollViewDirVertical(this));
                }
            }
        }

        private Type cellComponentType;
        private bool hasInit;
        private Action<Cell, int> onCellUpdate;
        private Canvas canvas;
        private Camera uiCamera;
        private PointerEventData eventData;
        private List<RaycastResult> touchList;
        private Mask viewportMask;
        private float prePos;
        private int fingerId = -1;
        private bool isDragging;

        private void OnDisable()
        {
            fingerId = -1;
            isDragging = false;
            hasTriggerHeadAction = false;
            hasTriggerEndAction = false;
        }

        void Awake()
        {
            if (Application.isPlaying)
            {
                if (!cellPrefab)
                {
                    Debug.LogError($"CellPrefab 为空");
                }
                else
                {
                    cellPrefab.gameObject.SetActive(false);
                }

                CanvasScaler canvasScaler = rectTransform.GetComponentInParent<CanvasScaler>();
                canvas = canvasScaler.GetComponent<Canvas>();
                if (canvas && canvas.renderMode != RenderMode.ScreenSpaceOverlay)
                {
                    uiCamera = canvas.worldCamera;
                }
            }
        }

        private void Init()
        {
            if (!viewport) return;

            CanvasScaler canvasScaler = transform.GetComponentInParent<CanvasScaler>();
            Canvas canvas = canvasScaler ? canvasScaler.GetComponent<Canvas>() : null;
            if (canvas && canvas.renderMode != RenderMode.ScreenSpaceOverlay)
            {
                uiCamera = canvas.worldCamera;
            }

            viewport.anchorMin = new Vector2(0, 0);
            viewport.anchorMax = new Vector2(1, 1);
            viewport.offsetMin = new Vector2(0, 0);
            viewport.offsetMax = new Vector2(0, 0);
            viewportSize = new Vector2(viewport.rect.width, viewport.rect.height);
            currDir.InitData(viewportSize);
            hasInit = true;
        }

        public void Update()
        {
            if (Application.isPlaying)
            {
                PlayModeUpdate();
            }
            else
            {
#if UNITY_EDITOR

                EditModeUpdate();
#endif
            }
        }

        /// <summary>
        /// 滑动到头部的时候触发，用于触发继续加载诸如聊天的历史数据
        /// </summary>
        public void SetScrollToHeadCallback(Action onScrollToHead)
        {
            this._onScrollToHead = onScrollToHead;
        }

        /// <summary>
        /// 滑动到末尾的时候触发，用于触发继续加载剩余的数据
        /// </summary>
        public void SetScrollToEndCallback(Action onScrollToEnd)
        {
            this._onScrollToEnd = onScrollToEnd;
        }

        /// <summary>
        /// 设置列表总条数和Cell刷新回调，以更新Cell上的内容
        /// </summary>
        public void SetCellUpdateCallback<T>(Action<T, int> callback) where T : Component
        {
            cellComponentType = typeof(T);
            onCellUpdate = (Cell cell, int index) => { callback?.Invoke(cell.component as T, index); };
        }

        /// <summary>
        /// 设置列表总条数和Cell刷新回调，以更新Cell上的内容
        /// </summary>
        /// <param name="total">数据总量</param>
        public void SetTotalNumber(int total)
        {
            isDragging = false;
            if (cellComponentType == null)
            {
                Debug.LogError("先调用 SetCellUpdateCallback<T>() 方法定义 T，才能调用 SetTotalNumber() 方法 ");
                return;
            }

            if (!hasInit) Init();

            try
            {
                if (total > this.totalDataCount)
                {
                    //新数据比旧数据多，做加法
                    this.totalDataCount = total;
                    int rowIndex = 0;
                    int cellIndex = rows.Count > 0 ? GetCurrFirstIndex() : 0;
                    bool hasFull = false;
                    bool createdAll = false;
                    headRow = null;
                    endRow = null;
                    while (!hasFull && !createdAll)
                    {
                        Row row = null;
                        if (rowIndex < rows.Count)
                        {
                            row = rows[rowIndex];
                            if (!row.IsFull)
                            {
                                (float x, float y) = currDir.GetInitPos();
                                row.OnReuse(x, y, ref cellIndex);
                            }
                            else
                            {
                                cellIndex += gridNum;
                            }
                        }
                        else
                        {
                            (float x, float y) = currDir.GetInitPos();
                            if (pool.Count > 0)
                            {
                                row = pool.Dequeue();
                                row.OnReuse(x, y, ref cellIndex);
                            }
                            else
                            {
                                row = _CreateNewRow(x, y, ref cellIndex);
                            }

                            rows.Add(row);
                        }

                        if (headRow == null)
                        {
                            headRow = row;
                        }

                        endRow = row;
                        
                        //好一个刷新一个，以便下一个拿到真实的高度
                        int maxSize = 0;
                        for (int i = 0; i < row.cells.Length; i++)
                        {
                            Cell cell = row.cells[i];
                            if (cell.trans.gameObject.activeSelf)
                            {
                                onCellUpdate?.Invoke(cell, cell.index);
                                if (direction == Direction.Horizontal)
                                {
                                    row.width =  cell.Width;
                                }
                                else
                                {
                                    row.height =  cell.Height;
                                }
                            }
                        }

                        hasFull = currDir.HasFull();
                        if (cellIndex >= total)
                        {
                            createdAll = true;
                        }

                        cellsExceedsView = currDir.IsCellsExceedsView();
                        rowIndex++;
                    }
                }
                else if (total <= this.totalDataCount)
                {
                    //新数据比旧数据少，做减法
                    this.totalDataCount = total;
                    if (total == 1)
                    {
                        ScrollToHead();
                    }
                    else if (total > 1)
                    {
                        int targetIndex = total - 1;
                        if (targetIndex < GetCurrFirstIndex())
                        {
                            ScrollToIndex(targetIndex);
                        }
                    }

                    for (int i = rows.Count - 1; i >= 0; i--)
                    {
                        Row row = rows[i];
                        bool allCellsNotActived = true;
                        for (int j = 0; j < row.cells.Length; j++)
                        {
                            Cell cell = row.cells[j];
                            if (cell.trans)
                            {
                                if (cell.trans.gameObject.activeSelf && cell.index >= totalDataCount)
                                {
                                    cell.trans.gameObject.SetActive(false);
                                }

                                if (cell.trans.gameObject.activeSelf)
                                {
                                    onCellUpdate?.Invoke(cell, cell.index);
                                    if (direction == Direction.Horizontal)
                                    {
                                        row.width =  cell.Width;
                                    }
                                    else
                                    {
                                        row.height =  cell.Height;
                                    }
                                    allCellsNotActived = false;
                                }
                            }
                        }

                        if (allCellsNotActived)
                        {
                            row.OnRecycle();
                            pool.Enqueue(row);
                            rows.RemoveAt(i);
                            if (rows.Count > 0)
                            {
                                endRow = rows[rows.Count - 1];
                            }
                        }
                    }

                    cellsExceedsView = currDir.IsCellsExceedsView();
                }
            }
            catch (Exception ex)
            {
                Debug.LogError(ex);
            }
        }

        /// <summary>
        /// 重新触发一次当前已显示的全部Cell回调
        /// </summary>
        public void Refresh()
        {
            isDragging = false;
            viewportSize = new Vector2(viewport.rect.width, viewport.rect.height);
            for (int i = 0; i < rows.Count; i++)
            {
                Row row = rows[i];
                for (int j = 0; j < row.cells.Length; j++)
                {
                    Cell cell = row.cells[j];
                    if (cell.trans.gameObject.activeSelf)
                    {
                        onCellUpdate?.Invoke(cell, cell.index);
                    }
                }
            }
        }

        /// <summary>
        /// 获取当前可见的展示在第一位的数据索引
        /// </summary>
        /// <returns></returns>
        public int GetCurrFirstIndex()
        {
            if (headRow == null)
            {
                return 0;
            }

            return headRow.GetHeadCellIndex();
        }

        /// <summary>
        /// 获取当前可见的展示在最后一位的数据索引
        /// </summary>
        /// <returns></returns>
        public int GetCurrLastIndex()
        {
            if (endRow == null)
            {
                return 0;
            }

            return endRow.GetHeadCellIndex();
        }

        /// <summary>
        /// 跳到头部
        /// </summary>
        public void ScrollToHead()
        {
            ScrollToIndex(0);
        }

        /// <summary>
        /// 跳到尾部
        /// </summary>
        public void ScrollToEnd(bool useAnim)
        {
            if (useAnim)
            {
                ScrollToIndex(totalDataCount - 1); //TODO 动画实现
            }
            else
            {
                ScrollToIndex(totalDataCount - 1);
            }
        }

        /// <summary>
        /// 跳到指定索引位置
        /// </summary>
        public void ScrollToIndex(int index)
        {
            if (index < 0) index = 0;
            if (index > totalDataCount - 1) index = totalDataCount - 1;

            //停止当前的运动
            velocity = 0;

            if (!cellsExceedsView)
            {
                //所有的都在视窗内了就别动了
                return;
            }

            //先全部回收
            for (int i = 0; i < rows.Count; i++)
            {
                Row row = rows[i];
                row.OnRecycle();
                pool.Enqueue(row);
            }

            rows.Clear();
            headRow = null;
            endRow = null;
            float x = 0, y = -space.y;
            switch (alignment)
            {
                case Alignment.LeftTop:
                    x = space.x;
                    break;
                case Alignment.RightTop:
                    x = viewportSize.x - space.x;
                    break;
            }

            //先从尾部刷起，若刷到视窗顶部还没刷到目标Cell,则可以放心反过来从头部往后刷
            bool hasFindFromEnd = false;
            int endRowFirstIndex = Mathf.CeilToInt(totalDataCount / (float)gridNum) * gridNum - gridNum;
            while (true)
            {
                Row row = null;
                if (pool.Count > 0)
                {
                    row = pool.Dequeue();
                    row.OnReuse(x, y, ref endRowFirstIndex);
                }
                else
                {
                    row = _CreateNewRow(x, y, ref endRowFirstIndex);
                }

                currDir.SetRowPos(row);
                row.UpdateCellsPos();
                if (endRow == null)
                {
                    endRow = row;
                }

                headRow = row;
                rows.Insert(0, row);
                if (endRowFirstIndex <= index)
                {
                    hasFindFromEnd = true;
                }

                if (currDir.CanBreak())
                {
                    break;
                }

                endRowFirstIndex -= gridNum * 2;
            }

            if (hasFindFromEnd) return;

            //先全部回收
            for (int i = 0; i < rows.Count; i++)
            {
                Row row = rows[i];
                row.OnRecycle();
                pool.Enqueue(row);
            }

            rows.Clear();
            headRow = null;
            endRow = null;
            int rowIndex = Mathf.FloorToInt(index / (float)gridNum);
            int beginIndex = rowIndex * gridNum;
            y = -space.y;
            switch (alignment)
            {
                case Alignment.LeftTop:
                    x = space.x;
                    break;
                case Alignment.RightTop:
                    x = viewportSize.x - space.x;
                    break;
            }

            while (true)
            {
                Row row = null;
                if (pool.Count > 0)
                {
                    row = pool.Dequeue();
                    row.OnReuse(x, y, ref beginIndex);
                }
                else
                {
                    row = _CreateNewRow(x, y, ref beginIndex);
                }

                if (headRow == null)
                {
                    headRow = row;
                }

                endRow = row;
                rows.Add(row);
                if (currDir.SetXY(row, ref x, ref y))
                {
                    break;
                }

                if (beginIndex >= totalDataCount)
                {
                    break;
                }
            }
        }

        /// <summary>
        /// 立即结束结尾的惯性缓动
        /// </summary>
        public void Stop()
        {
            velocity = 0;
        }

        public Row _CreateNewRow(float x, float y, ref int index)
        {
            Row row = new Row(this, x, y);
            row.cells = new Cell[gridNum];
            for (int i = 0; i < gridNum; i++)
            {
                Cell cell = new Cell(direction);
                cell.trans = Instantiate(cellPrefab, cellPrefab.parent, false);
                cell.trans.anchorMin = new Vector2(0, 1);
                cell.trans.anchorMax = new Vector2(0, 1);
                cell.trans.pivot = new Vector2(0.5f, 0.5f);
                cell.component = cell.trans.GetComponent(cellComponentType);
                if (!cell.component)
                {
                    Debug.LogError($"Cell 缺少脚本[ {cellComponentType.Name} ]");
                    return null;
                }

                if (index >= 0 && index < totalDataCount)
                {
                    if (!cell.trans.gameObject.activeSelf)
                    {
                        cell.trans.gameObject.SetActive(true);
                    }

                    cell.index = index;
                    onCellUpdate?.Invoke(cell, index);
                }
                else
                {
                    if (cell.trans.gameObject.activeSelf)
                    {
                        cell.trans.gameObject.SetActive(false);
                    }
                }

                row.cells[i] = cell;
                index++;
            }

            row.RefreshSize();
            row.UpdateCellsPos();
            return row;
        }

        private bool IsTouchInViewportRange(List<RaycastResult> raycasts)
        {
            for (int i = 0; i < raycasts.Count; i++)
            {
                GameObject node = raycasts[i].gameObject;
                if (node == viewport.gameObject)
                {
                    return true;
                }

                Transform parent = node.transform.parent;
                while (parent)
                {
                    if (parent == viewport.transform)
                    {
                        return true;
                    }

                    parent = parent.parent;
                }
            }

            return false;
        }

        private void PlayModeUpdate()
        {
            if (rows.Count == 0 || headRow == null) return;

            if (Application.isMobilePlatform)
            {
                if (fingerId == -1)
                {
                    for (int i = 0; i < Input.touchCount; i++)
                    {
                        Touch touch = Input.GetTouch(i);
                        if (touch.phase == TouchPhase.Began)
                        {
                            List<RaycastResult> raycasts = GetTouchAllUI(touch.position);
                            if (IsTouchInViewportRange(raycasts))
                            {
                                fingerId = touch.fingerId;
                                prePos = ScreenToUGUIPoint(touch.position);
                                isDragging = true;
                                break;
                            }
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < Input.touchCount; i++)
                    {
                        Touch touch = Input.GetTouch(i);
                        if (touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled)
                        {
                            if (touch.fingerId == fingerId)
                            {
                                fingerId = -1;
                                isDragging = false;
                                hasTriggerHeadAction = false;
                                hasTriggerEndAction = false;
                                break;
                            }
                        }
                    }
                }
            }
            else
            {
                if (Input.GetMouseButtonDown(0))
                {
                    List<RaycastResult> raycasts = GetTouchAllUI(Input.mousePosition);
                    if (IsTouchInViewportRange(raycasts))
                    {
                        prePos = ScreenToUGUIPoint(Input.mousePosition);
                        isDragging = true;
                    }
                }

                if (Input.GetMouseButtonUp(0))
                {
                    isDragging = false;
                    hasTriggerHeadAction = false;
                    hasTriggerEndAction = false;
                }
            }

            //求velocity
            if (isDragging)
            {
                if (Application.isMobilePlatform)
                {
                    for (int i = 0; i < Input.touchCount; i++)
                    {
                        Touch touch = Input.GetTouch(i);
                        if (touch.fingerId == fingerId)
                        {
                            float touchPos = ScreenToUGUIPoint(touch.position);
                            velocity = touchPos - prePos;
                            prePos = touchPos;
                            break;
                        }
                    }
                }
                else
                {
                    float touchPos = ScreenToUGUIPoint(Input.mousePosition);
                    velocity = touchPos - prePos;
                    prePos = touchPos;
                }

                //判断两端拉紧减速
                currDir.ReduceSpeed();
            }
            else
            {
                velocityScale = 1;
                //判断两端回弹
                if (!currDir.ElasticBack(0.3f))
                {
                    if (Mathf.Abs(velocity) > 1f)
                    {
                        velocity += (0 - velocity) * 0.05f;
                    }
                    else
                    {
                        velocity = 0;
                    }
                }
            }

            //附加velocity进行移动
            currDir.MoveHeadRow();
            headRow.UpdateCellsPos();
            if (rows.Count > 1)
            {
                for (int i = 1; i < rows.Count; i++)
                {
                    Row row = rows[i];
                    Row preRow = rows[i - 1];
                    if (row == headRow) continue;
                    currDir.MoveFollowHeadRow(row, preRow);
                    row.UpdateCellsPos();
                }
            }

            //判断变化屏幕外复用,仅内容超出视窗的情况使用
            if (cellsExceedsView)
            {
                currDir.Reuse();
            }
        }

        private List<RaycastResult> GetTouchAllUI(Vector2 screenPos)
        {
            eventData ??= new PointerEventData(EventSystem.current);
            eventData.pressPosition = screenPos;
            eventData.position = screenPos;
            touchList ??= new List<RaycastResult>();
            touchList.Clear();
            EventSystem.current.RaycastAll(eventData, touchList);
            return touchList;
        }

        private float ScreenToUGUIPoint(Vector3 screenPos)
        {
            RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, screenPos, uiCamera, out Vector2 uiPos);
            return currDir.GetTouchPos(uiPos);
        }

        private void EditModeUpdate()
        {
            if (!viewport) return;
            Init();
            viewportSize = new Vector2(viewport.rect.width, viewport.rect.height);
            int index = 0;
            while (true)
            {
                bool canBreak = false;
                for (int i = 0; i < gridNum; i++)
                {
                    if (index >= viewport.childCount)
                    {
                        canBreak = true;
                        break;
                    }

                    RectTransform child = viewport.GetChild(index) as RectTransform;

                    int rowIndex = Mathf.FloorToInt(index / (float)gridNum);
                    int gridIndex = index % gridNum;

                    child.anchorMin = new Vector2(0, 1);
                    child.anchorMax = new Vector2(0, 1);
                    child.pivot = new Vector2(0.5f, 0.5f); //Cell的锚点必须在中心，以方便做点击缩放
                    child.anchoredPosition = currDir.EditModeUpdatePos(child, rowIndex, gridIndex);
                    index++;
                }

                if (canBreak)
                {
                    break;
                }
            }
        }

#if UNITY_EDITOR
        [UnityEditor.MenuItem("CGFramework/创建 ScrollView")]
        [UnityEditor.MenuItem("GameObject/CGFramework/创建 ScrollView", priority = -2200)]
        private static void Create()
        {
            GameObject go = new GameObject("ScrollView");
            go.layer = LayerMask.NameToLayer("UI");
            go.transform.SetParent(UnityEditor.Selection.activeGameObject.transform, false);
            go.AddComponent<RectTransform>().sizeDelta = new Vector2(500, 500);
            (go.transform as RectTransform).pivot = new Vector2(0, 1);

            GameObject viewport = new GameObject("Viewport");
            viewport.layer = LayerMask.NameToLayer("UI");
            viewport.transform.SetParent(go.transform, false);
            var rectMask2D = viewport.AddComponent<RectMask2D>();
            rectMask2D.softness = new Vector2Int(0, 0);
            RectTransform viewportTrans = viewport.transform as RectTransform;
            viewportTrans.anchorMin = new Vector2(0, 0);
            viewportTrans.anchorMax = new Vector2(1, 1);
            viewportTrans.offsetMin = new Vector2(0, 0);
            viewportTrans.offsetMax = new Vector2(0, 0);
            viewportTrans.gameObject.AddComponent<ScrollViewViewport>();

            GameObject cell = new GameObject("Cell");
            cell.layer = LayerMask.NameToLayer("UI");
            cell.transform.SetParent(viewportTrans, false);
            cell.AddComponent<Image>();

            ScrollView scrollView = go.AddComponent<ScrollView>();
            scrollView.viewport = viewportTrans;
            scrollView.cellPrefab = cell.transform as RectTransform;

            UnityEditor.EditorUtility.SetDirty(go);
        }
#endif
    }
}